#ifndef __BUFFER_HPP__
#define __BUFFER_HPP__

#include <iostream>
#include <vector>
#include <cassert>

namespace logs
{
    #define DEFAULT_BUFFER_SIZE (1024*1024*100)
    #define THRESHOLD_BUFFER_SIZE (80*1024*1024)
    #define INCREMENT_BUFFER_SIZE (10*1024*1024)
    class Buffer
    {
    public:
        Buffer()
            :_buffer(DEFAULT_BUFFER_SIZE)
            ,_reader_idx(0)
            ,_writer_idx(0)
        {}

        void push(const char* data,size_t len)
        {
            ensureEnoughSize(len);
            std::copy(data,data+len,&_buffer[_writer_idx]);
            moveWriter(len);
        }

        const char* begin()
        {
            return &_buffer[_reader_idx];
        }

        size_t readAbleSize()
        {
            return (_writer_idx-_reader_idx);
        }

        size_t writeAbleSize()
        {
            return (_buffer.size()-_writer_idx);
        }

        void moveReader(size_t len)
        {
            assert(len<=readAbleSize());
            _reader_idx+=len;
        }

        void reset()
        {
            _reader_idx=0;
            _writer_idx=0;
        }

        void swap(Buffer& buffer)
        {   
            _buffer.swap(buffer._buffer);
            std::swap(_reader_idx,buffer._reader_idx);
            std::swap(_writer_idx,buffer._writer_idx);
        }

        bool empty()
        {
            return (_reader_idx==_writer_idx);
        }
    private:
        void moveWriter(size_t len)
        {
            assert(len<=writeAbleSize());
            _writer_idx+=len;
        }
        
        void ensureEnoughSize(size_t len)
        {
            if(len<=writeAbleSize()) return;
            size_t new_size=0;
            if(_buffer.size()<THRESHOLD_BUFFER_SIZE)
            {
                new_size=_buffer.size()*2+len;
            }
            else
            {
                new_size=_buffer.size()+INCREMENT_BUFFER_SIZE+len;
            }
            _buffer.resize(new_size);
        }
    
    private:
        std::vector<char> _buffer;//buffer缓冲区
        size_t _reader_idx;//读位置
        size_t _writer_idx;//写位置
    };
}

#endif